package com.ai.aspect;

import com.ai.common.utils.TraceContext;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Order(0)
@Aspect
@Component
public class LogAspect {
    @Pointcut("execution(public * com.ai.web.*Controller.*(..))")
    public void webAspect() {

    }

    @Around("webAspect()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        //获取目标对象对应的字节码对象
        Class<?> targetCls = joinPoint.getTarget().getClass();
        //获取方法签名信息从而获取方法名和参数类型
        Signature signature = joinPoint.getSignature();
        //将方法签名强转成MethodSignature类型，方便调用
        MethodSignature ms = (MethodSignature)signature;
        //通过字节码对象以及方法签名获取目标方法对象
        Method targetMethod = targetCls.getDeclaredMethod(ms.getName(),ms.getParameterTypes());
//        //获取目标方法上的注解指定的操作名称
//        GetMapping requiredLog = targetMethod.getAnnotation(GetMapping.class);
//        String[] values = requiredLog.value();
//        System.out.println("path = " + values[0]);
        //获取请求参数注解
        RequestLog requestLog = targetMethod.getAnnotation(RequestLog.class);
        //获取请求参数注解
        ResponseLog responseLog = targetMethod.getAnnotation(ResponseLog.class);
        if (requestLog == null && responseLog == null){
            return joinPoint.proceed();
        }
        String uid = "";
        //方法名称
        String methodName = joinPoint.getSignature().getName();
        //跳过文件上传接口
        if (methodName.contains("upload")){
            return joinPoint.proceed();
        }
        //请求路径
        String requestURI = null;

        //获取请求头和请求参数
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        if (sra != null) {
            HttpServletRequest request = sra.getRequest();
            requestURI = request.getRequestURI();
            // 如果有session则返回session如果没有则返回null(避免创建过多的session浪费内存)
            //HttpSession session = request.getSession(false);
            // 获取请求头
            Enumeration<String> enumeration = request.getHeaderNames();
            while (enumeration.hasMoreElements()) {
                String name = enumeration.nextElement();
                String value = request.getHeader(name);
                if ("uid".equals(name)){
                    uid = value;

                }
                //System.out.println("请求头 " + name + ":" + value);
            }
        }
        //保存用户id
        TraceContext.getCurrent().addTags("uid", uid);
        //获取请求参数
        Map<String, Object> parameterMap = new HashMap<>();
        parameterMap.put("uid",uid);
        Object[] args = joinPoint.getArgs();
        String[] names = ((CodeSignature) joinPoint.getSignature()).getParameterNames();
        for (int i = 0; i < names.length; i++) {
            parameterMap.put(names[i], args[i]);
        }

        if (requestLog != null) {
            //获取注解中的属性值
            boolean requestLogValue = requestLog.value();
            if (uid != null){
                log.info(requestURI + "：uid -> " + uid + " ,request -> " + JSON.toJSONString(parameterMap));
            }else {
                log.info(requestURI + "：request -> " + JSON.toJSONString(parameterMap));
            }
        }
        //业务方法
        Object res = joinPoint.proceed();

        if (responseLog != null) {
            log.info(requestURI + "：response -> " + JSON.toJSONString(res));
        }
        return res;
    }
}
